﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Drawing;

namespace TreeTraversal
{
    public class BinaryTreeNode<T>
    {
        public BinaryTreeNode(T value, BinaryTreeNode<T> parent)
        {
            Value = value;
            m_Parent = parent;
        }

        public T Value;
        BinaryTreeNode<T> m_Parent;
        BinaryTreeNode<T> m_Left;
        BinaryTreeNode<T> m_Right;

        public virtual BinaryTreeNode<T> Parent { get { return m_Parent; } set { m_Parent = value; } }
        public virtual BinaryTreeNode<T> Left { get { return m_Left; } set { m_Left = value; } }
        public virtual BinaryTreeNode<T> Right { get { return m_Right; } set { m_Right = value; } }
        public int Balance { get { return RightDepth - LeftDepth; } }
        public int LeftDepth = 0;
        public int RightDepth = 0;
        public int MaxDepth { get { return Math.Max(LeftDepth, RightDepth); } }
        //public bool HasAChild { get { return Left != null || Right != null; } }

        public ChildDirection GetDirection()
        {
            if (this.Parent == null)
                return ChildDirection.Undefined;

            if (this.Parent.Left == this)
                return ChildDirection.Left;
            else if (this.Parent.Right == this)
                return ChildDirection.Right;
            else
                Debug.Assert(false);

            return ChildDirection.Undefined;
        }

        Size m_NodeSize = new Size(38, 38);
        Font m_NodeValueFont = new Font(SystemFonts.DefaultFont.FontFamily, 9);
        Brush m_NodeValueBrush = Brushes.Black; //Brushes.Maroon;
        Brush m_NodeBackgroundBrush = Brushes.Green; //Brushes.Red;
        public virtual Size NodeImageSize
        {
            get { return m_NodeSize; }
        }

        enum Style
        { 
            Rectangle,
            Ellipse
        }
        Style m_Style = Style.Ellipse;

        public Bitmap GetNodeImage()
        {
            if (Parent == null)
            {
                m_NodeBackgroundBrush = Brushes.Red;
                m_NodeValueBrush = Brushes.Maroon;
            }
            else
            {
                m_NodeBackgroundBrush = Brushes.Turquoise;
                m_NodeValueBrush = Brushes.DarkCyan;
            }
            
            Bitmap bitmap = new Bitmap(m_NodeSize.Width, m_NodeSize.Height);
            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
                
                int shadowSize = 3;
                Point NodeCenter = new Point(((m_NodeSize.Width - shadowSize) / 2) + shadowSize, ((m_NodeSize.Height - shadowSize) / 2));

                Size nodeSize = new Size(m_NodeSize.Width - shadowSize - 1, m_NodeSize.Height - shadowSize - 1);

                using (Brush brush = new SolidBrush(Color.FromArgb(0x11, Color.Black)))
                {
                    Rectangle shadowRect = new Rectangle(new Point(0, shadowSize), nodeSize);
                    Rectangle nodeRect = new Rectangle(new Point(shadowSize, 0), nodeSize);
                    if (m_Style == Style.Ellipse)
                    {
                        graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                        graphics.FillEllipse(brush, shadowRect);
                        graphics.FillEllipse(m_NodeBackgroundBrush, nodeRect);
                    }
                    else if (m_Style == Style.Rectangle)
                    {
                        graphics.FillRectangle(brush, shadowRect);
                        graphics.FillRectangle(m_NodeBackgroundBrush, nodeRect);
                    }
                }

                //
                //
                
                //Point[] points = new Point[3];
                //points[0] = new Point(m_NodeSize.Width/2, 0);
                //points[1] = new Point(0, m_NodeSize.Height);
                //points[2] = new Point(m_NodeSize.Width, m_NodeSize.Height);
                //graphics.FillPolygon(
                //    m_NodeBackgroundBrush,
                //    points);

                graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                Font font = m_NodeValueFont;
                string value = Value.ToString();
                SizeF stringSize = graphics.MeasureString(value, font);
                graphics.DrawString(value, font, m_NodeValueBrush, NodeCenter.X - (stringSize.Width / 2), NodeCenter.Y - (stringSize.Height / 2));
            }
            return bitmap;
        }
    }

    public enum ChildDirection
    {
        Undefined,
        Left,
        Right
    }
}
